Skip to content

Review UI and suggest improvements#88

Merged
dan323 merged 3 commits into
masterfrom
task/review-ui-and-suggest-improvements-05575d
Mar 23, 2026
Merged

Review UI and suggest improvements#88
dan323 merged 3 commits into
masterfrom
task/review-ui-and-suggest-improvements-05575d

Conversation

@dan323

@dan323 dan323 commented Mar 23, 2026

Copy link
Copy Markdown
Owner

Summary

Reviewed the frontend UI and applied concrete improvements across usability, accessibility, and visual consistency:

  • Header: Replaced unstyled <h1> with a proper <header> banner and readable title.
  • App layout: Moved "New Proof" button out of position: absolute into a flexbox toolbar; added empty-state message when no proof is loaded.
  • Menu: Replaced alert() on failure with inline role="alert" error; added loading state ("Applying…"); relabeled button to "Apply Rule"; added keyboard focus ring styles.
  • NewProofModal: Added role="dialog", aria-modal, aria-labelledby; Escape closes modal; backdrop click closes; per-premise remove button; Submit disabled until goal is entered.
  • ProofViewer: Added aria-label to table and scope="col" to <th> for screen reader navigation; extracted inline <hr> styles to CSS.
  • Expressions.css: Reduced proof table font size from 3rem to 1.4rem; added row hover effect.

Opened by multi-repo-tasks via Claude Code.

Copilot AI review requested due to automatic review settings March 23, 2026 01:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines the frontend UI/UX for the natural deduction proof app, focusing on improved layout consistency and better accessibility semantics across key components.

Changes:

  • Improved overall app layout (toolbar + main area) and added empty-state messaging when no proof is loaded.
  • Enhanced accessibility and usability in the menu and modal (ARIA attributes, inline errors instead of alert(), loading/disabled states, keyboard handling).
  • Updated proof viewer/table markup and styling for readability and screen-reader navigation.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
frontend/src/App.tsx Adds toolbar/main layout and an empty-proof placeholder when no proof is loaded.
frontend/src/App.css Styles toolbar, focus rings, and empty-proof placeholder.
frontend/src/components/Header.tsx Wraps title in a styled <header> and updates copy.
frontend/src/components/Header.css Adds header banner styling.
frontend/src/components/menu/Menu.tsx Adds empty-state, inline error handling, loading state, and updates labels/copy.
frontend/src/components/menu/Menu.css Adds focus styles, empty-state styling, disabled/button styles, and inline error styling.
frontend/src/components/modal/NewProofModal.tsx Adds dialog ARIA, escape/backdrop close, premise removal UI, focus-on-open, and submit validation.
frontend/src/components/modal/NewProofModal.css Refreshes modal styling and adds premise-row/remove button styling + focus states.
frontend/src/components/proof/ProofViewer.tsx Adds table ARIA improvements and moves divider styling to CSS classes.
frontend/src/components/Expressions.css Reduces proof font sizes, adds hover styling, and introduces wrapper/divider styles.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 105 to 124
@@ -108,31 +114,57 @@ const Menu: FC<MenuProps> = ({ logic, onColorChange, setProof, proof }) => {
};

applyAction(logic, proof, actionDto, (response: ApplyActionResponse) => {
setIsLoading(false);
if (response.success) {
setProof(response.proof);
glowingColors.forEach((color) => onColorChange(color,-1));
} else {
console.error('Action failed:', response.message);
alert(`Action failed: ${response.message}`);
setErrorMessage(response.message || 'Action could not be applied.');
}
});

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isLoading is set to true before calling applyAction, but it’s only reset inside the success callback. If the underlying fetch rejects (see frontend/src/service/actions.ts where .catch(...) only logs and never invokes the consumer), the callback won’t run and the UI will stay stuck in the loading/disabled state. Consider handling promise rejections here (e.g., try/finally with await applyAction(...) or adding an error callback / making applyAction always invoke the consumer) so setIsLoading(false) runs on all paths and an error message is surfaced.

Copilot uses AI. Check for mistakes.
Comment on lines +137 to +165
<label htmlFor="action-select" className="menu-label">Select Inference Rule:</label>
<select
id="action-select"
className="menu-select"
value={selectedAction}
onChange={handleActionChange}
aria-label="Select inference rule"
>
<option value="">-- Choose a rule --</option>
{actions.map((action) => (
<option key={action.name} value={action.name}>
{action.name}
</option>
))}
</select>
{selectedInputs}
{errorMessage && (
<p className="menu-error" role="alert" aria-live="assertive">
{errorMessage}
</p>
)}
<button
className="menu-button"
onClick={processAction}
disabled={selectedAction === '' || isLoading}
aria-disabled={selectedAction === '' || isLoading}
>
{isLoading ? 'Applying…' : 'Apply Rule'}
</button>

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component’s behavior/labels changed (e.g., option text "-- Choose a rule --", button label "Apply Rule", removed alert() in favor of inline role="alert", and different GlowingInput labels). There are existing Jest/RTL tests for Menu that assert the old strings and window.alert usage, which will now fail. Please update the Menu tests to reflect the new UI and error-handling behavior.

Copilot uses AI. Check for mistakes.
Comment thread frontend/src/App.tsx Outdated
Comment on lines +53 to +75
const hasProof = proof.goal !== '';

return (
<div className="App">
<Header />
<button className="new-proof-btn" onClick={handleOpenModal}>
New Proof
</button>
<Menu logic={LOGIC} proof={proof} setProof={setProof} onColorChange={onColorChange} />
<Proof proof={proof} coloring={colorMapping} />

<div className="app-toolbar">
<button
className="new-proof-btn"
onClick={handleOpenModal}
aria-label="Start a new proof"
>
New Proof
</button>
</div>
<main className="app-main">
<Menu logic={LOGIC} proof={proof} setProof={setProof} onColorChange={onColorChange} />
{hasProof ? (
<Proof proof={proof} coloring={colorMapping} />
) : (
<div className="empty-proof-state" role="status">
<p>No proof loaded. Click <strong>New Proof</strong> to begin.</p>
</div>
)}

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasProof is currently derived from proof.goal !== '', while the Menu’s empty-state uses proof.steps.length === 0 && !proof.goal. If a proof ever has steps but an empty goal (e.g., from other flows/tests/service responses), App will show the empty-proof placeholder while Menu shows the rule-application UI, which is inconsistent and could hide an active proof. Consider basing both empty/loaded checks on the same predicate (e.g., proof.goal !== '' || proof.steps.length > 0).

Copilot uses AI. Check for mistakes.
Comment on lines +60 to 109
<h2 id="new-proof-modal-title">New Proof</h2>
<div className="modal-body">
<label>Premises:</label>
<label className="modal-section-label">Premises:</label>
{premises.map((premise, index) => (
<input
key={premise+index}
type="text"
value={premise}
onChange={(e) => handlePremiseChange(index, e.target.value)}
placeholder="Enter a premise"
/>
<div key={index} className="premise-row">
<input
ref={index === 0 ? firstInputRef : undefined}
id={`premise-${index}`}
type="text"
value={premise}
onChange={(e) => handlePremiseChange(index, e.target.value)}
placeholder={`Premise ${index + 1}`}
aria-label={`Premise ${index + 1}`}
/>
{premises.length > 1 && (
<button
className="remove-premise-btn"
onClick={() => handleRemovePremise(index)}
aria-label={`Remove premise ${index + 1}`}
title="Remove"
>
×
</button>
)}
</div>
))}
<button className="add-premise-btn" onClick={handleAddPremise}>
+ Add Premise
</button>

<label>Goal:</label>
<label htmlFor="modal-goal" className="modal-section-label">Goal:</label>
<input
id="modal-goal"
type="text"
value={goal}
onChange={(e) => handleGoalChange(e.target.value)}
placeholder="Enter the goal"
placeholder="Enter the goal expression"
/>
</div>
<div className="modal-footer">
<button className="submit-btn" onClick={handleSubmit}>
Submit
<button
className="submit-btn"
onClick={handleSubmit}
disabled={goal.trim() === ''}
>
Start Proof
</button>
<button className="close-btn" onClick={onClose}>
Close
Cancel
</button>

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are existing Jest/RTL tests for NewProofModal that assert the old placeholders ("Enter a premise" / "Enter the goal") and button labels ("Submit" / "Close"). With the new placeholders, "Start Proof"/"Cancel" labels, and the submit button now disabled until a goal is entered, those tests will fail unless updated to match the new UI and validation behavior.

Copilot uses AI. Check for mistakes.
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)
B Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@sonarqubecloud

Copy link
Copy Markdown

@dan323 dan323 merged commit 873f65f into master Mar 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants